package com.gwnet.cabinet.client;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gwnet.cabinet.config.ApiConfig;
import com.gwnet.cabinet.domian.base.Result;
import com.gwnet.cabinet.domian.base.UserSession;
import com.gwnet.cabinet.domian.bo.*;
import com.gwnet.cabinet.domian.vo.BoxVO;
import com.gwnet.cabinet.domian.vo.OpenBoxVO;
import com.gwnet.cabinet.domian.vo.TakeBoxVO;
import com.gwnet.cabinet.enums.ResultCodeEnum;
import com.gwnet.common.core.exception.base.BaseException;
import com.gwnet.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.util.LinkedList;
import java.util.List;

/**
 * @author: WangLiang
 * @date: 2024/7/22 11:13
 */
@Slf4j
@Component
public class ApiClient {

    private final RestTemplate restTemplate = new RestTemplate();

    private final static String MINI_TOKEN_KEY = "mini:token";

    /** 登录接口地址 */
    private final static String LOGIN = "/mini/login/login";

    /** 开箱接口地址 */
    private final static String OPEN_BOX = "/mini/home/divideOpenBox";

    /** 取出接口地址 */
    private final static String TAKE_BOK = "/mini/home/takeBox";

    /** 查询指定箱门状态接口地址 */
    private final static String GET_BOX_STATUS = "/mini/home/getBoxStatus";

    /** 下发管理箱门指令 */
    private final static String MANAGER_BOXES = "/mini/home/managerBoxes";

    private final ApiConfig apiConfig;

    public ApiClient(ApiConfig apiConfig) {
        this.apiConfig = apiConfig;
    }


    /**
     * 获取请求头信息
     * @return
     */
    private HttpHeaders getHeader(){
        // 401->登录已失效
        UserSession userSession = login();

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set("MiniToken",userSession.getMini_token());
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }


    /**
     * 获取箱子的状态列表
     * @param getBoxStatusBO
     * @return
     */
    public List<BoxVO> getBoxStatus(GetBoxStatusBO getBoxStatusBO){
        List<BoxVO> list = new LinkedList<>();
        // 请求地址
        String url = apiConfig.getBaseUrl() + GET_BOX_STATUS;

        HttpHeaders headers = getHeader();
        HttpEntity<GetBoxStatusBO> requestEntity = new HttpEntity<>(getBoxStatusBO, headers);

        log.info("=========打印入参：{}",requestEntity.getBody().toString());
        log.info("=========打印url：{}",url);

        // 发送POST请求
        ResponseEntity<Result> responseEntity = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                new ParameterizedTypeReference<Result>() {}
        );

        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            Result result = responseEntity.getBody();
            log.info("=========打印响应：{}",result);

            // 请求成功
            if(result.getCode().equals(ResultCodeEnum.SUCCESS.code())){
                JSONArray boxList = JSONObject.parseArray(JSONObject.toJSONString(result.getData()));
                for (Object object : boxList) {
                    BoxVO boxBO = JSONObject.parseObject(JSONObject.toJSONString(object), BoxVO.class);
                    list.add(boxBO);
                }
                return list;
            } else if(result.getCode().equals(ResultCodeEnum.VALIDATE_FAIL.code())){
                // 身份验证失败，清除缓存重试
                this.cleanCache();
                this.getBoxStatus(getBoxStatusBO);
            }
        }
        return null;

    }


    /**
     * 下发管理箱门指令，可远程开箱
     * @param managerBoxesBO
     * @return
     */
    public Result managerBoxes(ManagerBoxesBO managerBoxesBO){

        // 请求地址
        String url = apiConfig.getBaseUrl() + MANAGER_BOXES;

        HttpHeaders headers = getHeader();
        HttpEntity<ManagerBoxesBO> requestEntity = new HttpEntity<>(managerBoxesBO, headers);

        log.info("=========打印入参：{}",requestEntity.getBody().toString());
        log.info("=========打印url：{}",url);

        // 发送POST请求
        ResponseEntity<Result> responseEntity = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                new ParameterizedTypeReference<Result>() {}
        );

        Result result = responseEntity.getBody();
        log.info("=========打印响应：{}",result);
        if(result.getCode().equals(ResultCodeEnum.VALIDATE_FAIL.code())){
            // 身份验证失败，清除缓存重试
            this.cleanCache();
            this.managerBoxes(managerBoxesBO);
        }

        return result;
    }


    /**
     * 取出
     * @param takeBoxBO 取出入参实体
     * @return 取出结果
     */
    public TakeBoxVO takeBox(TakeBoxBO takeBoxBO){
        // 请求地址
        String url = apiConfig.getBaseUrl() + TAKE_BOK;

        HttpHeaders headers = getHeader();
        HttpEntity<TakeBoxBO> requestEntity = new HttpEntity<>(takeBoxBO, headers);

        log.info("=========打印入参：{}",requestEntity.getBody().toString());
        log.info("=========打印url：{}",url);

        // 发送POST请求
        ResponseEntity<Result> responseEntity = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                new ParameterizedTypeReference<Result>() {}
        );

        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            Result result = responseEntity.getBody();
            log.info("=========打印响应：{}",result);

            // 请求成功
            if(result.getCode().equals(ResultCodeEnum.SUCCESS.code())){
                TakeBoxVO takeBoxVO = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), TakeBoxVO.class);
                return takeBoxVO;
            } else if(result.getCode().equals(ResultCodeEnum.VALIDATE_FAIL.code())){
                // 身份验证失败，清除缓存重试
                this.cleanCache();
                this.takeBox(takeBoxBO);
            }
        }
        return null;
    }


    /**
     * 开箱
     * @param openBoxBO 开箱入参实体
     * @return 开箱结果
     */
    public OpenBoxVO openBox(OpenBoxBO openBoxBO) {
        // 请求地址
        String url = apiConfig.getBaseUrl() + OPEN_BOX;

        HttpHeaders headers = getHeader();
        HttpEntity<OpenBoxBO> requestEntity = new HttpEntity<>(openBoxBO, headers);

        log.info("=========打印入参：{}",requestEntity.getBody().toString());
        log.info("=========打印url：{}",url);

        // 发送POST请求
        ResponseEntity<Result> responseEntity = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                new ParameterizedTypeReference<Result>() {}
        );

        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            log.info("=========打印响应：{}",responseEntity.getBody());

            if(responseEntity.getBody().getCode().equals(ResultCodeEnum.SUCCESS.code())){
                String jsonString = JSONObject.toJSONString(responseEntity.getBody().getData());
                OpenBoxVO openBoxVO = JSONObject.parseObject(jsonString,OpenBoxVO.class);
                return openBoxVO;
            } else if(responseEntity.getBody().getCode().equals(ResultCodeEnum.VALIDATE_FAIL.code())){
                // 身份验证失败，清除缓存重试
                this.cleanCache();
                this.openBox(openBoxBO);
            } else if(responseEntity.getBody().getCode().equals(ResultCodeEnum.ALREADY_USED.code())){
                // 抛出异常，全局处理
                throw new BaseException("请求第三方快递柜接口出现问题");
            }


        } else {
            // 处理错误情况
            // 这里可以根据需要返回一个失败的Result，或者抛出异常
            // retry * 3 做重试
            return null;
        }
        return null;
    }

    /**
     * 登录
     * @return
     */
    public UserSession login(){
        log.info("=========执行登录开始==========");
        Boolean hasKey = RedisUtils.hasKey(MINI_TOKEN_KEY);
        if(hasKey){
            Object userSessionObj = RedisUtils.getCacheObject(MINI_TOKEN_KEY);
            UserSession userSession = JSONObject.parseObject(userSessionObj.toString(), UserSession.class);
            log.info("=========获取上次登录结果缓存成功，打印缓存结果：{}==========",userSession);
            return userSession;
        }

        // 请求参数
        LoginBO loginBO = new LoginBO();
        BeanUtils.copyProperties(apiConfig,loginBO);
        // 请求地址
        String url = apiConfig.getBaseUrl() + LOGIN;

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 创建请求体
        HttpEntity<LoginBO> requestEntity = new HttpEntity<>(loginBO, headers);

        // 发送POST请求
        ResponseEntity<Result<UserSession>> responseEntity = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                new ParameterizedTypeReference<Result<UserSession>>() {}
        );

        // 检查响应状态
        if (responseEntity.getStatusCode().is2xxSuccessful()) {
            // 存入Redis，API说管理端的token一个月过期，暂存redis二十天失效
            UserSession userSession = responseEntity.getBody().getData();
            RedisUtils.setCacheObject(MINI_TOKEN_KEY,JSONObject.toJSONString(userSession),Duration.ofDays(20));
            log.info("=========执行登录成功，打印登录结果：{}==========",userSession);
            return userSession;
        } else {
            // 处理错误情况
            // 这里可以根据需要返回一个失败的Result，或者抛出异常
            return null;
        }

    }


    /**
     * 清除缓存
     * @return
     */
    private boolean cleanCache(){
        // 清除缓存
        boolean flag = RedisUtils.deleteObject(MINI_TOKEN_KEY);
        return flag;
    }




}
